#include <iostream>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <cstring>
#include <string>
#include <sys/socket.h>
#include <unistd.h>
#include "Thread.hpp"

using namespace std;

void Usage(char *head)
{
    cout << "Use Err" << endl;
    cout << head << " ip port" << endl;
}

struct TaskData
{
    TaskData(struct sockaddr_in &local, int sock)
        : _local(local), _sock(sock)
    {
    }
    struct sockaddr_in _local;
    int _sock;
};

void sned_task(const struct TaskData &td)
{
    while (true)
    {
        string buffer;
        cout << "Enter # ";
        getline(std::cin, buffer);
        ssize_t n = sendto(td._sock, buffer.c_str(), buffer.size(), 0, (struct sockaddr *)&(td._local), sizeof(td._local));
        if (n > 0)
        {
            cout <<"send message: "<< buffer << endl;
        }
        else
        {
            cout << "send faualt" << endl;
        }
    }
}

 void recv_task(const struct TaskData& td)
{
    char retbuffer[1024];
    while (true)
    {
        struct sockaddr_in local;
        socklen_t len = sizeof(local);
        ssize_t n = recvfrom(td._sock, retbuffer, sizeof(retbuffer) - 1, 0, (struct sockaddr *)&local, &len);
        if (n > 0)
        {
            retbuffer[n] = 0;
            cerr << retbuffer << endl;
        }
        else
        {
            break;
        }
    }
}

int main(int argc, char *argv[])
{

    if (argc != 3)
    {
        Usage(argv[0]);
        return 1;
    }

    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        return 1;
    }

    struct sockaddr_in local;
    memset(&local, 0, sizeof(local));
    local.sin_family = AF_INET;
    local.sin_port = htons(stoi(argv[2]));
    local.sin_addr.s_addr = inet_addr(argv[1]);
    socklen_t len = sizeof(local);

    struct TaskData td(local, sockfd);
    Thread<TaskData> send_server("send", sned_task, td);
    Thread<TaskData> recv_server("server", recv_task, td);

    send_server.Start();
    recv_server.Start();
    

    send_server.Join();
    recv_server.Join();

    close(sockfd);
    return 0;
}